package org.vaadin.dotmap;

import org.vaadin.dotmap.client.ui.DotMapConnector.HighlightControl;
import org.vaadin.dotmap.client.ui.DotMapState;
import org.vaadin.dotmap.client.ui.VDotMap.Highlight;

import com.vaadin.terminal.ClassResource;
import com.vaadin.terminal.Resource;
import com.vaadin.terminal.gwt.client.communication.URLReference;
import com.vaadin.terminal.gwt.server.ResourceReference;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.Root;

/**
 * Shows a map of the world consisting of 'punched out' (transparent) holes in a
 * solid background. Highlight spots can be added behind the map image, so that
 * the dots seem to light up. Alternatively, highlights can be added on top of
 * the map image. Highlight fade away after a configurable delay, and both the
 * map image and the highlight image can be customized. The map dot color can
 * also easily be set.
 */
public class DotMap extends AbstractComponent {

    private final String DEFAULT_MAP = "dotmap.gif";
    private final String DEFAULT_HIGHLIGHT = "white.png";

    private Resource highlightImage;
    private long fadeMsec = 5000;

    public DotMap() {
        setMapImage(new ClassResource(getClass(), DEFAULT_MAP, Root
                .getCurrentRoot().getApplication()));
        setHighlightImage(new ClassResource(getClass(), DEFAULT_HIGHLIGHT, Root
                .getCurrentRoot().getApplication()));
    }

    public long getFadeMsec() {
        return fadeMsec;
    }

    public void setFadeMsec(long fadeMsec) {
        this.fadeMsec = fadeMsec;
        requestRepaint();
    }

    public Resource getMapImage() {
        URLReference r = getState().getMapImage();
        if (r == null) {
            return null;
        } else {
            return ((ResourceReference) r).getResource();
        }
    }

    /**
     * Set image to use as map image. The map must be a Mercator projection,
     * with the exception that it can be cropped from the top - see
     * {@link #setTopCrop(int)}.
     * 
     * @param mapImage
     */
    public void setMapImage(Resource mapImage) {
        getState().setMapImage(new ResourceReference(mapImage));
        requestRepaint();
    }

    public String getDotColor() {
        return getState().getMapColor();
    }

    /**
     * The color used for the dots, i.e the 'punched out' (transparent) holes in
     * the map image, as a HTML color string (e.g "red", "#ff0000", "#f00");
     * 
     * @param color
     */
    public void setDotColor(String color) {
        getState().setMapColor(color);
        requestRepaint();
    }

    public int getTopCrop() {
        return getState().getTopCrop();
    }

    /**
     * Sets how many pixels are missing from the top of the Mercator projection.
     * This enables you to leave out some areas where not a lot of stuff is
     * going on usually. To crop the bottom, use {@link #setHeight(String)}.
     * 
     * @param croppedPixels
     */
    public void setTopCrop(int croppedPixels) {
        getState().setTopCrop(croppedPixels);
        requestRepaint();
    }

    public Resource getHighlightImage() {
        return highlightImage;
    }

    /**
     * Set the image used by default as highlight image. You can also choose a
     * custom image when showing each highlight.
     * 
     * @param highlightImage
     */
    public void setHighlightImage(Resource highlightImage) {
        this.highlightImage = highlightImage;
        requestRepaint();
    }

    private String getResourceURL(Resource r) {
        return new ResourceReference(r).getURL();
    }

    /**
     * Shows a highlight at the specified position, using the default highlight
     * image, fade time, and z-index.
     * 
     * @param lat
     * @param lon
     */
    public void showHighlight(double lat, double lon) {
        Highlight h = new Highlight(lat, lon);
        h.setFadeMsec(fadeMsec);
        h.setImg(getResourceURL(highlightImage));
        showHighlight(h);
    }

    public void showHighlight(double lat, double lon, URLReference image,
            long fadeMsec, int zindex) {
        String imageURL = null;
        if (image != null) {
            imageURL = image.getURL();
        }
        showHighlight(new Highlight(lat, lon, imageURL, fadeMsec, zindex));
    }

    public void showHighlight(double lat, double lon, Resource image,
            long fadeMsec, int zindex) {
        ResourceReference imgref = new ResourceReference(image);
        showHighlight(lat, lon, imgref, fadeMsec, zindex);
    }

    public void showHighlight(double lat, double lon, URLReference image) {
        String imageURL = null;
        if (image != null) {
            imageURL = image.getURL();
        }
        Highlight h = new Highlight(lat, lon);
        h.setFadeMsec(fadeMsec);
        h.setImg(imageURL);
        showHighlight(h);
    }

    public void showHighlight(double lat, double lon, Resource image) {
        ResourceReference imgref = new ResourceReference(image);
        showHighlight(lat, lon, imgref);
    }

    /**
     * Shows a highlight at the specified position, using the specified
     * highlight image, fade time, and z-index.
     * 
     * @param lat
     * @param lon
     */
    public void showHighlight(Highlight highlight) {
        getRpcProxy(HighlightControl.class).showHighlight(highlight);
    }

    @Override
    public DotMapState getState() {
        return (DotMapState) super.getState();
    }

}
